/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package wat.serwerapp.usermgmt.ldap;

import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.naming.Name;
import javax.naming.NameClassPair;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.BasicAttribute;
import javax.naming.directory.BasicAttributes;
import javax.naming.directory.DirContext;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
import javax.naming.ldap.LdapName;

/**
 *
 * @author tarni
 */
// klasa zarzadzania uzytkownikami w serwerze LDAP
public final class UserManager extends wat.serwerapp.usermgmt.UserManager {

    private Map<String, User> buffer = new HashMap<String, User>();

    protected wat.serwerapp.usermgmt.UserManager.User getUserPom(String login, String password) throws NamingException {
        User user = buffer.get(login);
        if (user == null) {
            user = new User(login, password);
            buffer.put(login, user);
        }
        return user;
    }

    protected Set<wat.serwerapp.usermgmt.UserManager.User> getAllUsersPom() throws NamingException {
        System.out.println("getAllUsers method...");
        HashSet<wat.serwerapp.usermgmt.UserManager.User> users = new HashSet<wat.serwerapp.usermgmt.UserManager.User>();
        DirContext ctx = LdapConnector.getRolesContext();
        NamingEnumeration<NameClassPair> list = ctx.list("ou=users,dc=wat,dc=edu,dc=pl");
        while (list.hasMore()) {
            NameClassPair nc = list.next();
            String cn = nc.getName();
            User user = new User(cn);
            users.add(user);
        }
        return users;
    }

    protected void addUserPom(String userName, String userFullName, String password) {
        try {
            System.out.println("addUser method...");
            DirContext ctx = LdapConnector.getRolesContext();

            Attributes att = new BasicAttributes();
            Attribute c = new BasicAttribute("objectClass");
            c.add("person");
            c.add("top");
            c.add("simpleSecurityObject");
            c.add("organizationalPerson");
            att.put(c);

            Attribute a = new BasicAttribute("sn", userFullName);
            Attribute b = new BasicAttribute("userPassword", password);
            att.put(a);
            att.put(b);

            ctx.createSubcontext("cn=" + userName + User.USER_SUFIX, att);
        } catch (NamingException ex) {
            Logger.getLogger(RoleManager.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    protected void removeUserPom(String userName) {
        try {
            DirContext ctx = LdapConnector.getRolesContext();
            ctx.destroySubcontext("cn=" + userName + User.USER_SUFIX);
        } catch (NamingException ex) {
            Logger.getLogger(RoleManager.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    class User extends wat.serwerapp.usermgmt.UserManager.User {

        private static final String ROLES_ATTRIBUTE_NAME = "memberOf";
        private static final String SN_ATTRIBUTE_NAME = "sn";
        static final String USER_SUFIX = ",ou=users,dc=wat,dc=edu,dc=pl";
        static final String ROLE_BASE = "ou=roles,dc=wat,dc=edu,dc=pl";
        private DirContext ctx;
        private String cn;
        private Set<String> roles;
        private String fullName;

        User(String login, String password) throws NamingException {
            this.ctx = LdapConnector.getUserContext(login, password);
            this.cn = "cn=" + login + USER_SUFIX;
        }

        User(String cn) throws NamingException {
            this.ctx = LdapConnector.getRolesContext();
            this.cn = cn + USER_SUFIX;
        }

        public Map<String, String> getAllRights() throws NamingException {
            HashMap<String, String> allRights = new HashMap<String, String>();

            Set<String> tmpRoles = getRoles();

            for (String role : tmpRoles) {
                Map<String, String> rights = RoleManager.getRights(role);
                Set<String> rightNames = rights.keySet();
                for (String rightName : rightNames) {
                    allRights.put(rightName, rights.get(rightName));
                }
            }
            return allRights;
        }

        public Set<String> getRoles() throws NamingException {
            if (roles == null) {
                roles = new HashSet<String>();
                String filter = "(objectclass=groupOfUniqueNames)";
                String memberAttr = "uniqueMember";
                String cnAttr = "cn";
                String[] attrIDs = {cnAttr, memberAttr};
                SearchControls ctls = new SearchControls();
                ctls.setReturningAttributes(attrIDs);
                ctls.setSearchScope(SearchControls.SUBTREE_SCOPE);
                NamingEnumeration answer = ctx.search(ROLE_BASE, filter, ctls);

                while (answer.hasMoreElements()) {
                    SearchResult sr = (SearchResult) answer.next();

                    Attributes attrs = sr.getAttributes();
                    if (attrs != null) {
                        try {
                            String role = "";

                            for (NamingEnumeration ae = attrs.getAll(); ae.hasMore();) {
                                Attribute attr = (Attribute) ae.next();
                                if (attr.getID().equals(cnAttr)) {
                                    role = (String) cnAttr + "=" + attr.get() + "," + ROLE_BASE;
                                    break;
                                }
                            }
                            if (!role.isEmpty()) {
                                for (NamingEnumeration ae = attrs.getAll(); ae.hasMore();) {
                                    Attribute attr = (Attribute) ae.next();
                                    if (attr.getID().equals(memberAttr)) {
                                        int i = 0;
                                        for (NamingEnumeration e = attr.getAll(); e.hasMore(); i++) {
                                            if (cn.equals(e.nextElement().toString())) {
                                                roles.add(role);
                                                break;
                                            }
                                        }
                                    }
                                }
                            }

                        } catch (NamingException e) {
                            System.out.println("Problem listing members: " + e);
                        }
                    }
                }            
            }
            return roles;
        }

        @Deprecated
        public void setRoles(Set<String> rights) throws NamingException {
            Attributes att = ctx.getAttributes(cn);
            Attribute rolesLdap = att.get(ROLES_ATTRIBUTE_NAME);

            if (rolesLdap == null) {
                rolesLdap = new BasicAttribute(ROLES_ATTRIBUTE_NAME);
                att.put(rolesLdap);
            }

            getRoles().clear();
            rolesLdap.clear();

            for (String rightName : rights) {
                if (getRoles().contains(rightName)) {
                    System.out.println("Uzytkownik posiada juz te role: " + rightName);
                } else {
                    rolesLdap.add(rightName);
                    getRoles().add(rightName);
                }
            }
            ctx.modifyAttributes(cn, ctx.REPLACE_ATTRIBUTE, att);
        }

        @Deprecated
        public void addRole(String roleName) throws NamingException {
            if (getRoles().contains(roleName)) {
                System.out.println("Uzytkownik posiada juz te role: " + roleName);
            } else {
                Attributes att = ctx.getAttributes(cn);
                Attribute rolesLdap = att.get(ROLES_ATTRIBUTE_NAME);
                rolesLdap.add(roleName);
                getRoles().add(roleName);
                ctx.modifyAttributes(cn, ctx.REPLACE_ATTRIBUTE, att);
            }
        }

        @Deprecated
        public void removeRole(String roleName) throws NamingException {

            if (!getRoles().contains(roleName)) {
                System.out.println("Uzytkownik nie posiada takiej roli: " + roleName);
            } else {
                Attributes att = ctx.getAttributes(cn);
                Attribute rolesLdap = att.get(ROLES_ATTRIBUTE_NAME);
                rolesLdap.remove(roleName);
                getRoles().remove(roleName);
                ctx.modifyAttributes(cn, ctx.REPLACE_ATTRIBUTE, att);
            }
        }

        public String getFullName() throws NamingException {
            if (fullName == null) {
                Attributes att = ctx.getAttributes(cn);
                Attribute a = att.get(SN_ATTRIBUTE_NAME);

                fullName = (String) a.get();
            }

            return fullName;
        }

        public String getName() {
            int bI = 3;
            int eI = cn.indexOf(USER_SUFIX);
            return cn.substring(bI, eI);
        }
    }
}
